package org.custom.spring.boot.datasource.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import org.custom.spring.boot.datasource.config.DynamicRoutingDataSource;
import org.custom.spring.boot.datasource.entity.datasource.CustomDataSourceProperties;
import org.custom.spring.boot.datasource.exception.TipException;
import org.custom.spring.boot.datasource.mapper.CustomDataSourcePropertiesMapper;
import org.custom.spring.boot.datasource.service.DataSourceBuilder;
import org.custom.spring.boot.datasource.service.DataSourceService;
import org.custom.spring.boot.datasource.service.DynamicDatasourceService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.Objects;

import static org.custom.spring.boot.datasource.constant.JettExceptionConstant.SOMETHING_NOT_EMPTY;

/**
 * 数据源相关服务接口实现
 *
 * @author 李坤
 * @date 2022/3/31 15:05
 */
@Service("dataSourceService")
public class DataSourceServiceImpl implements DataSourceService {
    @Resource
    private Snowflake snowflake;
    @Resource
    private DynamicDatasourceService dynamicDatasourceService;
    @Resource
    private CustomDataSourcePropertiesMapper customDataSourcePropertiesMapper;

    @Override
    public List<CustomDataSourceProperties> findAllCustomDataSourceProperties() {
        return customDataSourcePropertiesMapper.selectAll();
    }

    @Override
    public boolean try2ConnectDataSource(CustomDataSourceProperties dataSourceProperties) {
        DataSource dataSource = dynamicDatasourceService.generateDataSource(dataSourceProperties);
        return Objects.nonNull(dataSource) && Objects.nonNull(dynamicDatasourceService.obtainConnection(dataSource));
    }

    @Override
    public List<CustomDataSourceProperties> findCustomDataSourcePropertiesByOwner(String owner) {
        return customDataSourcePropertiesMapper.selectAllByOwner(DynamicRoutingDataSource.DynamicDataSourceUtil.obtainUserId());
    }

    @Override
    public List<CustomDataSourceProperties> obtainWithLoadCustomDataSourceProperties() {
        // 查询该用户名下的数据源配置信息
        List<CustomDataSourceProperties> customDataSourceProperties = customDataSourcePropertiesMapper
                .selectAllByOwner(DynamicRoutingDataSource.DynamicDataSourceUtil.obtainUserId());

        // 加载数据源数据到动态数据源中
        for (CustomDataSourceProperties dataSourceProperties : customDataSourceProperties) {
            dynamicDatasourceService.appendDataSource(dataSourceProperties);
        }
        return customDataSourceProperties;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveCustomDataSourceProperties(CustomDataSourceProperties dataSourceProperties) {
        // 判断数据源名称是否为空，并创建数据源
        if (StrUtil.isNotEmpty(dataSourceProperties.getName())) {
            // 自定义数据源构建服务
            DataSourceBuilder dataSourceBuilder;
            // 获取默认数据源类型（该数据可能为空）
            Class<? extends DataSource> dataSourceClass = dynamicDatasourceService.getDefaultDataSourceClass();
            // 填充相关属性并判断是否为新增操作
            boolean isInsertOperate = this.inputCustomDataSourceProperties(dataSourceProperties, dataSourceClass);

            // 将数据源添加到动态数据源中
            dynamicDatasourceService.appendDataSource(dataSourceProperties);
            // 将数据源配置信息保存到数据库中
            return this.operateCustomDataSourceProperties(dataSourceProperties, isInsertOperate);
        }
        throw new TipException(String.format(SOMETHING_NOT_EMPTY, "数据源名称"));
    }

    /*-------------------------------------------------private methods------------------------------------------------*/

    /**
     * 保存或更新数据源配置属性
     *
     * @param dataSourceProperties 数据源配置属性
     *
     * @return 是否操作成功
     */
    private boolean operateCustomDataSourceProperties(CustomDataSourceProperties dataSourceProperties, boolean isInsertOperate) {
        return (isInsertOperate ? customDataSourcePropertiesMapper.insert(dataSourceProperties) : customDataSourcePropertiesMapper.update(dataSourceProperties)) == 1;
    }

    /**
     * 向 dataSourceProperties 中填充相关属性
     *
     * @param dataSourceProperties 数据源配置属性
     * @param dataSourceClass      数据源类型
     *
     * @return 是否为新增
     */
    private boolean inputCustomDataSourceProperties(CustomDataSourceProperties dataSourceProperties, Class<? extends DataSource> dataSourceClass) {
        // 原始的动态数据源ID标识
        String dynamicDataSourceId;
        // 是否为新增
        boolean isNew = StrUtil.isEmpty(dynamicDataSourceId = dataSourceProperties.getId());

        // 设置数据源类型
        dataSourceProperties.setType(dataSourceClass);
        // 设置数据源标识
        dataSourceProperties.setId(isNew ? snowflake.nextIdStr() : dynamicDataSourceId);
        // 设置数据源所有者
        dataSourceProperties.setOwner(DynamicRoutingDataSource.DynamicDataSourceUtil.obtainUserId());

        return isNew;
    }
}
